﻿using JNPF.Common.Configuration;
using JNPF.Common.Core.Security;
using JNPF.Common.Extension;
using JNPF.Common.Options;
using JNPF.Common.Security;
using JNPF.DependencyInjection;
using JNPF.EventBus;
using JNPF.EventHandler;
using JNPF.Systems.Entitys.System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using SqlSugar;

namespace JNPF.TaskScheduler.Listener;

/// <summary>
/// 定时任务监听器.
/// </summary>
public class SpareTimeListener : ISpareTimeListener, ISingleton
{
    private readonly IEventPublisher _eventPublisher;
    public IServiceProvider Services { get; }
    private readonly ConnectionStringsOptions _connectionStrings;

    /// <summary>
    /// 构造函数.
    /// </summary>
    public SpareTimeListener(IEventPublisher eventPublisher, IServiceProvider services, IOptions<ConnectionStringsOptions> connectionOptions)
    {
        _eventPublisher = eventPublisher;
        Services = services;
        _connectionStrings = connectionOptions.Value;
    }

    /// <summary>
    /// 监听所有任务.
    /// </summary>
    /// <param name="executer"></param>
    /// <returns></returns>
    public async Task OnListener(SpareTimerExecuter executer)
    {
        switch (executer.Status)
        {
            // 执行开始通知
            case 0:
                // Console.WriteLine($"{executer.Timer.WorkerName} 任务开始通知");
                break;

            // 任务执行之前通知
            case 1:
                // Console.WriteLine($"{executer.Timer.WorkerName} 执行之前通知");
                break;

            // 执行成功通知
            case 2:

            // 任务执行失败通知
            case 3:
                await RecoreTaskLog(executer);
                break;

            // 任务执行停止通知
            case -1:
                // Console.WriteLine($"{executer.Timer.WorkerName} 执行停止通知");
                break;

            // 任务执行取消通知
            case -2:
                // Console.WriteLine($"{executer.Timer.WorkerName} 执行取消通知");
                break;
        }
    }

    /// <summary>
    /// 记录日志
    /// </summary>
    /// <param name="executer"></param>
    /// <returns></returns>
    private async Task RecoreTaskLog(SpareTimerExecuter executer)
    {
        if (executer.Timer.Description.IsNotEmptyOrNull())
        {
            var TenantId = executer.Timer.Description.Split("/")[0];
            var TenantDbName = executer.Timer.Description.Split("/")[1];

            using var scope = Services.CreateScope();
            var _repository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<TimeTaskEntity>>();
            if (KeyVariable.MultiTenancy)
            {
                if (TenantId == null) return;
                _repository.Context.AddConnection(new ConnectionConfig()
                {
                    DbType = (DbType)Enum.Parse(typeof(DbType), _connectionStrings.DBType),
                    ConfigId = TenantId, // 设置库的唯一标识
                    IsAutoCloseConnection = true,
                    ConnectionString = string.Format(_connectionStrings.DefaultConnection, TenantDbName)
                });
                _repository.Context.ChangeDatabase(TenantId);
            }

            var taskEntity = await _repository.FirstOrDefaultAsync(x => x.Id == executer.Timer.WorkerName);
            var nextRunTime = ((DateTimeOffset)SpareTime.GetCronNextOccurrence(taskEntity.ExecuteCycleJson)).DateTime;

            await _eventPublisher.PublishAsync(new TaskEventSource("Task:UpdateTask", TenantId, TenantDbName, new TimeTaskEntity()
            {
                Id = taskEntity.Id,
                NextRunTime = nextRunTime,
            }));

            await _eventPublisher.PublishAsync(new TaskLogEventSource("Log:CreateTaskLog", TenantId, TenantDbName, new TimeTaskLogEntity()
            {
                Id = SnowflakeIdHelper.NextId(),
                TaskId = executer.Timer.WorkerName,
                RunTime = DateTime.Now.AddSeconds(10),
                RunResult = executer.Status == 2 ? 0 : 1,
                Description = executer.Status == 2 ? "执行成功" : "执行失败,失败原因:" + executer.Timer.Exception.ToJsonString()
            }));
        }
    }
}
